#pragma once 

#include <iostream>
#include "Connection.hpp"
#include "Reactor.hpp"

class IoService : public Connection 
{
    const int num = 1024;
public:
    IoService(int socketfd)
        :_socketfd(socketfd)
    {
        SetConnectionFd(_socketfd);
        SetNonBlock(_socketfd);
        Setevents(EPOLLIN | EPOLLET);
    }

    void Reader() override 
    {
        //进来的时候，肯定是就绪状态，但是你如何确定一次性把数据读取完毕了呢？？ 循环 + 非阻塞
        while(true)
        {
            char inbuffer[num];
            int n = ::recv(_socketfd,inbuffer,sizeof(inbuffer)-1,0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                //保存到我们connection的接受缓冲区中
                AppendReadBuffer(inbuffer);
            }
            else if(n == 0)
            {
                //交给异常处理，对端断开连接
                Exceptor();
                return ;
            }
            else 
            {
                //
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    LOG(LogLevel::DEBUG) << "数据读取完毕";
                    //这个时候也说明读取完毕了，没有数据准备就绪了
                    break; 
                }
                else if (errno == EINTR) //被信号打断了，继续读取
                    continue;
                else 
                {
                    //读取异常，可能对端已经断开连接了
                    Exceptor();
                    return ;
                }
            }
        }

        //到了这里说明已经一次性吧数据读取完毕了，但是是否读取为一个完整的报文不确定
        // 根据协议进行判断完整的报文，处理得到完整的报文
        std::string result_str = _handler(GetInbuffer());
        //添加到发送缓冲区
        AppendOutBuffer(result_str);
        //
        if (!IsOutBufferempty()) 
        {
            Sender(GetOutbuffer());
        }
    }
    void Sender(std::string&out) override
    {
        while(true)
        {
            int n = ::send(Fd(),out.c_str(),out.size(),0);
            if (n > 0)
            {
                Discard(n);
            }
            else if( n == 0) break;
            else 
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK) //缓冲区满了，等会再发，需要让epoll关系读事件了
                {
                    //让epoll给我关心写事件/ET模式
                    GetOwner()->EnableReadWrite(Fd(),true,true);
                    break;
                }
                else if(errno == EINTR)
                    continue;
                else  //对端可能断开连接了
                {
                    Exceptor();
                    return;
                }
            }
        }
        
    }    
    void Exceptor() override 
    {
        //对端断开连接
        LOG(LogLevel::INFO) << "client quite: " << Fd();
        GetOwner()->DeleteConnection(Fd());
    }
    ~IoService() override 
    {}
private:
    int _socketfd;
};  